﻿Public Class Configuration
  Private _surfaces As New List(Of ControlSurface)
  Private _nextSceneColIndex As Integer = 0
  Private _dpiFactor As Single = 0.0F

  Public Property ActualScaleFactor() As Single
    Get
      Return Me._dpiFactor
    End Get
    Set(ByVal value As Single)
      Me._dpiFactor = value
    End Set
  End Property

  Public ReadOnly Property Surfaces() As List(Of ControlSurface)
    Get
      Return Me._surfaces
    End Get
  End Property

  Private Function CreateSurface() As Integer
    Dim sc As New ControlSurface
    sc.Index = Me._nextSceneColIndex
    Me._nextSceneColIndex += 1
    Me._surfaces.Add(sc)
    Return sc.Index
  End Function

  Private Sub Clear()
    For Each sc As ControlSurface In Me._surfaces
      sc.Clear()
    Next
    Me._surfaces.Clear()
  End Sub

  Public Sub LoadControlsFromINI()
    Me.Clear()
    Me.CreateSurface() ' Music (0)
    Me.CreateSurface() ' Podcast (1)
    Me.CreateSurface() ' Radio (2)

    ' Open the INI file
    Dim bini As New Ini.File

    ' Load from the INI file
    bini.LoadFile(Settings.INIControlsPath)

    ' Fetch the main configuration section
    Dim bms As Ini.Section = bini.Section("MAIN")
    If bms IsNot Nothing Then
      Dim cl(2) As Integer
      cl(0) = Integer.Parse(bms.IntegerValueNoNull("C0L"))
      cl(1) = Integer.Parse(bms.IntegerValueNoNull("C1L"))
      cl(2) = Integer.Parse(bms.IntegerValueNoNull("C2L"))

      For scCol As Integer = 0 To 2 ' 3 Surfaces
        For sc As Integer = 0 To cl(scCol) - 1 ' "sc" scenes in each collection
          Me._surfaces(scCol).Scenes.Add(New ControlScene())

          Dim bsc As Ini.Section = bini.Section("C" & scCol & "S" & sc)
          If bsc IsNot Nothing Then
            Dim bscl As Integer = Integer.Parse(bsc.IntegerValueNoNull("SL"))
            For strip As Integer = 0 To bscl - 1 ' "strip" Rows in each scene
              Me._surfaces(scCol).Scenes(sc).Rows.Add(New ControlRow)

              Dim buttons As Integer = Integer.Parse(bsc.IntegerValueNoNull("R" & strip & "L"))
              For bt As Integer = 0 To buttons - 1
                Dim btkey As String = bsc.StringValue("R" & strip & "B" & bt)
                If btkey IsNot Nothing Then
                  Dim func As Integer = 0
                  Dim arg As Integer = 0
                  Dim btsplit() As String = btkey.Split(":")

                  If btsplit.Length = 1 Then
                    func = Integer.Parse(btsplit(0))
                  ElseIf btsplit.Length = 2 Then
                    func = Integer.Parse(btsplit(0))
                    arg = Integer.Parse(btsplit(1))
                  Else
                    Throw New Exception("CONTROL " & "R" & strip & "B" & bt & " is invalid format.")
                  End If

                  If func > 0 Then
                    ' Add existing button
                    Me._surfaces(scCol).Scenes(sc).Rows(strip).Buttons.Add(New ControlButton(func, arg))
                  Else
                    ' Add an empty button
                    Me._surfaces(scCol).Scenes(sc).Rows(strip).Buttons.Add(New ControlButton(ControlFunctions.Functions.NONE, 0))
                  End If
                Else
                  Throw New Exception("CONTROL NOT FOUND : " & "R" & strip & "B" & bt)
                End If
              Next
            Next
          Else
            Throw New Exception("SURFACE SECTION NOT FOUND : " & "C" & scCol & "S" & sc)
          End If
        Next

        Me._surfaces(scCol).CurrentSceneIndex = 0
      Next
    Else
      Throw New Exception("MAIN SECTION NOT FOUND")
    End If
  End Sub

  Public Sub SaveControlsToINI()
    SaveSurfacesCollectionToINI(Me._surfaces, Settings.INIControlsPath)
  End Sub

  Public Shared Sub SaveSurfacesCollectionToINI(ByVal surfaces As List(Of ControlSurface), ByVal iniFile As String)
    Dim bini As New Ini.File

    If surfaces.Count <> 3 Then
      Throw New InvalidSurfaceCountException
    End If

    ' Define main section
    bini.AddSection("Main")
    With bini.Section("Main")
      .IntegerValue("C0L") = surfaces(0).Scenes.Count
      .IntegerValue("C1L") = surfaces(1).Scenes.Count
      .IntegerValue("C2L") = surfaces(2).Scenes.Count
    End With

    ' Write out all containers
    For i As Integer = 0 To surfaces.Count - 1
      ' Write out container (i) scenes
      For j As Integer = 0 To surfaces(i).Scenes.Count - 1
        bini.AddSection("C" & i.ToString & "S" & j.ToString)
        With bini.Section("C" & i.ToString & "S" & j.ToString)
          .IntegerValue("SL") = surfaces(i).Scenes(j).Rows.Count
          ' Write out all scene (j) rows
          For k As Integer = 0 To surfaces(i).Scenes(j).Rows.Count - 1
            .IntegerValue("R" & k.ToString & "L") = surfaces(i).Scenes(j).Rows(k).Buttons.Count
            ' Write out all row (k) buttons
            For l As Integer = 0 To surfaces(i).Scenes(j).Rows(k).Buttons.Count - 1
              .StringValue("R" & k.ToString & "B" & l.ToString) = surfaces(i).Scenes(j).Rows(k).Buttons(l).FunctionString
            Next
          Next
        End With
      Next
    Next

    bini.Save(iniFile, True)
  End Sub

  Public Class InvalidSurfaceCountException
    Inherits Exception
  End Class
End Class
